Skip to content

Conversation

@chargome
Copy link
Member

No description provided.

github-actions bot and others added 20 commits October 21, 2025 16:03
[Gitflow] Merge master into develop
Fixes: #17809

Implements message truncation logic that drops oldest messages first
until the payload fits within the 20KB limit. If a single message
exceeds the limit, its content is truncated from the end. Supports
OpenAI/Anthropic ({ role, content }) and Google GenAI ({ role, parts: [{
text }] }) message formats.
No breaking changes that affect us:
https://github.com/pahen/madge/blob/master/CHANGELOG.md#v800

Should reduce our total dependency count.
This PR adds automatic instrumentation for LangChain chat clients in
Node SDK, we cover most used providers mentioned in
https://python.langchain.com/docs/integrations/chat/.

**What's added?**

TLDR; a [LangChain Callback Handler
](https://js.langchain.com/docs/concepts/callbacks/) that:

- Creates a stateful callback handler that tracks LangChain lifecycle
events
-  Handles LLM/Chat Model events (start, end, error, streaming)
-  Handles Chain events (start, end, error)
- Handles Tool events (start, end, error)
- Extracts and normalizes request/respo


**How it works?**
1. **Module Patching**: When a LangChain provider package is loaded
(e.g., `@langchain/anthropic`), the instrumentation:
   - Finds the chat model class (e.g., `ChatAnthropic`)
   - Wraps the `invoke`, `stream`, and `batch` methods on the prototype
   - Uses a Proxy to intercept method calls

2. **Callback Injection**: When a LangChain method is called:
   - The wrapper intercepts the call
- Augments the `options.callbacks` array with Sentry's callback handler
   - Calls the original method with the augmented callbacks
   
   
The integration is **enabled by default** when you initialize Sentry in
Node.js:

```javascript
import * as Sentry from '@sentry/node';
import { ChatAnthropic } from '@langchain/anthropic';

Sentry.init({
  dsn: 'your-dsn',
  tracesSampleRate: 1.0,
  sendDefaultPii: true, // Enable to record inputs/outputs
});

// LangChain calls are automatically instrumented
const model = new ChatAnthropic({
  model: 'claude-3-5-sonnet-20241022',
});

await model.invoke('What is the capital of France?');
```

You can configure what data is recorded:

```javascript
Sentry.init({
  integrations: [
    Sentry.langChainIntegration({
      recordInputs: true,  // Record prompts/messages
      recordOutputs: true, // Record responses
    })
  ],
});
```

Note: We need to disable integrations for AI providers that LangChain
use to avoid duplicate spans, this will be handled in a follow up PR.
This PR:
- Includes bindings from child loggers as attributes
- Tests that track/untrack setting is propagated to child loggers
ATM there are failing Hono E2E tests (e.g.
[here](https://github.com/getsentry/sentry-javascript/actions/runs/18714106732/job/53370082672?pr=17998)),
which print out following:

```sh
Error: src/index.ts(20,3): error TS2584: Cannot find name 'console'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'dom'.
```

The reason was, that the types were not there yet. I just wonder why it
was working before. In follow up PRs I will try to update Cloudflare
tests with its integrations.
There were 2 major changes:

- `auto.console.logging` -> `auto.log.console`
- `auto.logging.*` -> `auto.log.*`

This can go in already, I am just not sure if this should be a breaking
change or a minor bump, since theoretically dashboards or bookmarked
searches/groupings would be failing.

(closes #17900)
This adds two new options into the `nativeNodeFetchIntegration` - the
only thing it does is passing the two new options directly into the OTel
instrumentation. Since this is OTel related, this is only accessible
within the `node` SDK.

The documentation will be then updated for the fetch integration ([it
seems](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/nodefetch/)
that also the `spans` are missing)

(closes #17953)
[Next 16 was
released](https://github.com/vercel/next.js/releases/tag/v16.0.0)

With that proxy files run per default on nodejs.

This PR
- Updates the tests to run on next 16 (non-beta)
- Adds support for handling middleware transactions in the node part of
the sdk
Closes: #17861 

This adds
- instrumentation of Cloud Functions for Firebase (v2) along side the
Firestore integration. It can be used with the
`Sentry.firebaseIntegration()` (this is atm not documented in the docs
and got added in #16719, but will be added right after this has been
merged. See getsentry/sentry-docs#15247).
- The test app for Firebase has been rewritten and updated since it
requires a little special setup.

<details>
<summary>Supported functions</summary>
<ul>
  <li>onRequest</li>
  <li>onCall</li>
  <li>onDocumentCreated</li>
  <li>onDocumentUpdated</li>
  <li>onDocumentDeleted</li>
  <li>onDocumentWritten</li>
  <li>onDocumentCreatedWithAuthContext</li>
  <li>onDocumentUpdatedWithAuthContext</li>
  <li>onDocumentDeletedWithAuthContext</li>
  <li>onDocumentWrittenWithAuthContext</li>
  <li>onSchedule</li>
  <li>onObjectFinalized</li>
  <li>onObjectArchived</li>
  <li>onObjectDeleted</li>
  <li>onObjectMetadataUpdated</li>
</ul>
</details>

Bear in mind that the OTel attributes for FaaS are still in
[Development](https://opentelemetry.io/docs/specs/semconv/faas/faas-spans/)
and could change or be removed over time (not sure if we should then
even add them in here at this point in time).
This is currently a bandaid fix to remove the `chalk` import statements
that break turbopack apps during runtime until we have more details how
this code gets bundled into production.

ref #17806
closes #17691
Currently, the test in this PR fail:
#17789

Root routes can yield an empty transaction name, causing `<unlabeled
transaction>` instead of `/` as the transaction name for the root.
This happens when the router includes children routes with `index:
true`.

The route matching is also depending on the `allRoutes` Set. The
`allRoutes` Set include the children routes twice (once as children of
the route and once as a root element of the Set). When only including
them once, it works but parametrization does not work anymore.
--> First I thought, this duplication is the cause but probably it isn't

## What’s broken
Root cause is in `sendIndexPath(...)`:
- Mis-parenthesized ternary picks `stripBasenameFromPathname` instead of
`pathBuilder`.
  - Trimming turns `/` into an empty string.
…on (#17986)

Adds support for LangChain manual instrumentation in @sentry/cloudflare
and @sentry/vercel-edge.
To instrument LangChain operations, create a callback handler with
Sentry.createLangChainCallbackHandler and pass it to your LangChain
invocations.

```
import * as Sentry from '@sentry/cloudflare';
import { ChatAnthropic } from '@langchain/anthropic';

// Create a LangChain callback handler
const callbackHandler = Sentry.createLangChainCallbackHandler({
  recordInputs: true,   // Optional: record input prompts/messages
  recordOutputs: true   // Optional: record output responses
});

// Use with chat models
const model = new ChatAnthropic({
  model: 'claude-3-5-sonnet-20241022',
  apiKey: 'your-api-key'
});

await model.invoke('Tell me a joke', {
  callbacks: [callbackHandler]
});
```

The callback handler automatically creates spans for:

- Chat model invocations (gen_ai.chat)
- LLM invocations (gen_ai.pipeline)
- Chain executions (gen_ai.invoke_agent)
- Tool executions (gen_ai.execute_tool)
…m api (#18007)

The issue surfaced when `message.stream` was used in conjunction with
the `stream: true` option which would lead to us returning async results
instead of the expected MessageStream from anthropic ai.

We now take this into account and tightened the types.

Closes: #17977
It seems that the size limit was not enforced and a PR could be merged
without the job being green:
…7789)

Co-authored-by: s1gr1d <sigrid.huemer@posteo.at>
Co-authored-by: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com>
…atibility (#18013)

- Migrated from Jest `done` callback to [Promise-based async test
pattern](https://vitest.dev/guide/migration.html#done-callback)
- Fixed test assertion by adding missing `</head>` tag to trigger
`getTraceMetaTags` call (the test did not work before as
`getTraceMetaTags` is only called when there is a closing `head` tag
- Corrected stream piping logic to properly test transformer
functionality
The getMetaTagTransformer function internally pipes the transformer TO
the bodyStream (`htmlMetaTagTransformer.pipe(body)`). So the correct
flow is:
  1. Write data to the transformer
  2. Transformer processes it and pipes to bodyStream
  3. Read the output from bodyStream
…sactions (#17962)

Fixes an issue where `pageload` and `navigation` transactions have
incorrect (URL-based or wildcard-based) names when the span is cancelled
early before lazy routes finish loading.

This occurs when `document.hidden` triggers early span cancellation
(e.g., user switches tabs during page load). In React Router
applications with lazy routes, the parameterized route information may
not be available yet when the span ends, resulting in transaction names
like `/user/123/edit` (URL-based) or `/projects/*/views/*`
(wildcard-based) instead of the correct parameterized route like
`/user/:id/edit` or `/projects/:projectId/views/:viewId`.

This fix patches `span.end()` to perform a final route resolution check
before the span is sent, using the live global `allRoutes` Set to
capture any lazy routes that loaded after the span was created but
before it ended.
@chargome chargome self-assigned this Oct 23, 2025
{
name: `execute_tool ${toolName}`,
op: 'gen_ai.execute_tool',
attributes: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The LangChain integration uses <code>asString()</code> to serialize messages, bypassing the truncation logic (<code>getTruncatedJsonString()</code>) used by other AI integrations.
Severity: HIGH | Confidence: 1.00

🔍 Detailed Analysis

The LangChain callback handler serializes AI request messages using `asString()`, which does not enforce any size limits. Other AI integrations like OpenAI and Anthropic use `getTruncatedJsonString()` to truncate messages to a 20KB limit before sending them as span attributes. This inconsistency means that large LangChain message payloads can be sent to Sentry, bypassing the intended size restrictions and potentially causing issues with data storage and bandwidth for users.

💡 Suggested Fix

Replace the direct call to asString() with getTruncatedJsonString() when setting the GEN_AI_REQUEST_MESSAGES_ATTRIBUTE for LangChain messages. This will ensure that LangChain messages are truncated using the same logic as other AI integrations, adhering to the 20KB size limit.

🤖 Prompt for AI Agent
Fix this bug. In packages/core/src/utils/langchain/index.ts at line 256: The LangChain
callback handler serializes AI request messages using `asString()`, which does not
enforce any size limits. Other AI integrations like OpenAI and Anthropic use
`getTruncatedJsonString()` to truncate messages to a 20KB limit before sending them as
span attributes. This inconsistency means that large LangChain message payloads can be
sent to Sentry, bypassing the intended size restrictions and potentially causing issues
with data storage and bandwidth for users.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix in a follow-up cc @RulaKhaled

@github-actions
Copy link
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.63 kB added added
@sentry/browser - with treeshaking flags 23.11 kB added added
@sentry/browser (incl. Tracing) 40.97 kB added added
@sentry/browser (incl. Tracing, Profiling) 45.26 kB added added
@sentry/browser (incl. Tracing, Replay) 79.29 kB added added
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 68.97 kB added added
@sentry/browser (incl. Tracing, Replay with Canvas) 83.99 kB added added
@sentry/browser (incl. Tracing, Replay, Feedback) 96.16 kB added added
@sentry/browser (incl. Feedback) 41.3 kB added added
@sentry/browser (incl. sendFeedback) 29.29 kB added added
@sentry/browser (incl. FeedbackAsync) 34.22 kB added added
@sentry/react 26.31 kB added added
@sentry/react (incl. Tracing) 42.97 kB added added
@sentry/vue 29.11 kB added added
@sentry/vue (incl. Tracing) 42.75 kB added added
@sentry/svelte 24.64 kB added added
CDN Bundle 26.9 kB added added
CDN Bundle (incl. Tracing) 41.62 kB added added
CDN Bundle (incl. Tracing, Replay) 77.87 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback) 83.35 kB added added
CDN Bundle - uncompressed 78.86 kB added added
CDN Bundle (incl. Tracing) - uncompressed 123.44 kB added added
CDN Bundle (incl. Tracing, Replay) - uncompressed 238.48 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 251.24 kB added added
@sentry/nextjs (client) 45.11 kB added added
@sentry/sveltekit (client) 41.4 kB added added
@sentry/node-core 50.75 kB added added
@sentry/node 157.81 kB added added
@sentry/node - without tracing 92.63 kB added added
@sentry/aws-serverless 106.35 kB added added

@github-actions
Copy link
Contributor

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 8,727 - - added
GET With Sentry 1,361 16% - added
GET With Sentry (error only) 6,023 69% - added
POST Baseline 1,180 - - added
POST With Sentry 509 43% - added
POST With Sentry (error only) 1,043 88% - added
MYSQL Baseline 3,279 - - added
MYSQL With Sentry 454 14% - added
MYSQL With Sentry (error only) 2,668 81% - added

@chargome chargome merged commit 2bde42b into master Oct 23, 2025
378 of 380 checks passed
@chargome chargome deleted the prepare-release/10.22.0 branch October 23, 2025 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants